module Main exposing (..)

import Html as H exposing (Html, div, text, program)
import Html.Events exposing (onClick)
import Html.Attributes as HA
-- import Html.Events as E
import NewProcess.Core as NP
import ProcessQueue.Core as PQ
import ProcessQueue.Model as PQM exposing (PCB)

import Time


-- MODEL

-- 主模型
type alias Model =
    { title: String
    -- 添加新进程
    , new_process : NP.Model
    -- 进程队列
    , process_queue : PQM.Model
    -- 打印调试
    , print : String
    }


init : ( Model, Cmd Msg )
init =
    ( {title = "模拟线程调度"
      ,new_process = NP.empty_process
      ,print = ""
      ,process_queue = PQ.empty_model
      }
    , Cmd.none 
    )



-- MESSAGES


type Msg
    = New_process_msg NP.Msg
    | Process_queue_msg PQ.Msg
    | Tick Time.Time 



-- VIEW


view : Model -> Html Msg
view model =
    H.div
      []
      -- [ H.h1 [] [ H.text (.title model)]
      -- , H.br [] []
      -- 组件: 添加新进程
      [ H.map New_process_msg (NP.view (.new_process model))
      -- 组件: 进程队列
      , H.map Process_queue_msg (PQ.view (.process_queue model))
      -- , H.br [] []
      -- 调试用打印
      -- , H.text ("调试打印: " ++ (.print model))
      -- , H.br [] []
      -- , H.button [onClick (Tick 1000)] [H.text "点我触发tick"]
      , tick_button
      ]


tick_button : Html Msg
tick_button =
  div [HA.id "runner",onClick (Tick 1000)] [div [] [text "单步运行程序"]]

pcb : NP.Model -> Maybe PCB
pcb np =
  let name = .name np
      cost = (.cost >> String.toInt) np
  in case cost of
      Err err -> Nothing
  
      Ok val -> Just (PCB name val 0)


-- 处理信号，信号是子模块跟父模块交互的唯一方法
process_np_signal : NP.OutSignal -> Model -> Model
process_np_signal signal model =
  case signal of
    NP.No_signal -> model

    NP.Add_process_signal new_process -> 
      let maybe_pcb = pcb new_process
      in case maybe_pcb of
        Nothing -> model

        Just pcb -> 
          -- let new_process_queue = PQ.with_new_pcb (.process_queue model) pcb
          let new_process_queue = PQ.on_pcb_add (.process_queue model) pcb
          in {model | process_queue = new_process_queue}

-- UPDATE


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        New_process_msg sub_msg -> 
          let (sub_model,sub_cmd,signal) = 
                (NP.update sub_msg (.new_process model))

              new_model =
                process_np_signal signal {model | new_process = sub_model}

          in (new_model,Cmd.none)

        Process_queue_msg sub_msg ->
          (model,Cmd.none)

        Tick time -> 
          ( { model | process_queue = PQ.tick (.process_queue model)
                    , print = "tick: " ++ ((.process_queue >> .pointer >> toString) model) } ,Cmd.none)



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model = Sub.none
  -- Time.every Time.second Tick
  



-- MAIN


main : Program Never Model Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }